package lib

import (
	"bytes"
	"context"
	"crypto"
	"crypto/md5"
	crand "crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/base64"
	"encoding/json"
	"encoding/pem"
	"errors"
	"fmt"
	"git.900sui.cn/kc/kcgin"
	"git.900sui.cn/kc/kcgin/logs"
	"git.900sui.cn/kc/rpcPay/common/lib/tool"
	"git.900sui.cn/kc/rpcinterface/interface/pay"
	"github.com/shopspring/decimal"
	"github.com/tidwall/gjson"
	"golang.org/x/crypto/pkcs12"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"sort"
	"strconv"
	"strings"
	"time"
)

//获取token请求参数
type GetTokenReq struct {
	ApplicationID string
	PK            string
	DN            string
	RandomNumber  string
	RsaSign       string
	SDKType       string
}

//响应token结构体
type ReplyToken struct {
	ErrorCode      string `json:"errorCode"`
	AppAccessToken string `json:"appAccessToken"`
}

type payData struct {
	TraderNo          string //商户号
	TraderOrderNo     string //订单号
	OrderSendTime     string //商户系统订单生成时间
	OrderName         string //订单名称
	PayModeNo         string //支付方式
	AuthCode          string //授权码
	TranAmt           string //交易金额
	SubTraderPublicId string //微信公众号|小程序appid
	UserSubId         string //微信用户openid
	OrderRemark       orderRemark
}

type syshead struct {
	AppAccessToken string //AppAccessToken信息
	ApplicationID  string //appId
	SDKType        string //sdk版本信息
	MrchCode       string //平台代码
	CnsmrSeqNo     string //请求流水号
}

//订单备注明细结构体
type orderRemark struct {
	Oderlist     []orderList
	SFJOrdertype string //订单类型 1=子订单
	Remarktype   string `json:"remarktype"` //备注类型 默认取值 JHS0100000
	PlantCode    string `json:"plantCode"`  //平台代码
}

//订单备注中的订单订单列表结构体
type orderList struct {
	PayModel   string //支付模式 0-冻结支付 1-普通支付
	TranFee    string //手续费  单位 ：元； 金额为两位小数格式，例如0.01。注意是字符串、而非数字类型。
	SubAccNo   string //入账会员子账户
	Subamount  string `json:"subamount"`  //子订单金额 单位 ：元； 金额为两位小数格式，例如0.01。注意是字符串、而非数字类型。
	SuborderId string `json:"suborderid"` //子订单号 不可超过22位，且全局唯一
	Object     string `json:"object"`     //子订单简单描述
}

type pinganpay struct {
	privateKey       string //私钥证书
	publicKey        string //公钥证书
	privateKeySecret string //私钥密码
	traderNo         string //商户号
	apiUrl           string //后台类api地址
	frontApiUrl      string //前台类收银台api地址
	apiTokenUrl      string //token 接口地址
	appId            string //appid
	mrchCode         string //平台代码
	uid              string //用户短号
	PriKey           *rsa.PrivateKey
	notifyUrl        string //回调地址-云收款
	frontUrl         string //前端跳转地址
	wxMchid          string //微信商户号
	wxAppid          string //微信appid
	wxUrl            string //微信支付url
	wxNotifyUrl      string //回调地址-微信
}

//微信支付订单金额
type wxPayAmount struct {
	Total    int    `json:"total"`    //订单总金额，单位为分
	Currency string `json:"currency"` //货币类型 CNY：人民币
}

//微信app预支付请求结构体
type wxPay struct {
	Appid       string      `json:"appid"`        //应用ID
	Mchid       string      `json:"mchid"`        //直连商户号
	Description string      `json:"description"`  //商品描述
	OutTradeNo  string      `json:"out_trade_no"` //商户订单号
	NotifyUrl   string      `json:"notify_url"`   //通知地址
	Amount      wxPayAmount `json:"amount"`       //订单金额
	//SceneInfo	SceneInfo	`json:"scene_info"`
}

const (
	//上海
	CHANNELAREA = 321

	//杭州
	CHANNELHANGZHOU = 383

	//#支付渠道
	//平安云收款
	CHANNELPAY_pingan = "PINANPAY"
	//微信直连
	CHANNELPAY_wx = "WXPAY"
	//支付宝直连
	CHANNELPAY_ali = "ALIPAY"
)

var PinganPay *pinganpay

//初始化
func (p *pinganpay) Init(cid int) (err error) {
	//上海区域参数化

	switch cid {
	case CHANNELAREA :
		PinganPay = &pinganpay{
			privateKey:       kcgin.AppConfig.String("pingan.shPrivateKey"),
			publicKey:        kcgin.AppConfig.String("pingan.shPublicKey"),
			privateKeySecret: kcgin.AppConfig.String("pingan.shPrivateKeySecret"),
			traderNo:         kcgin.AppConfig.String("pingan.shTraderNo"),
			apiUrl:           kcgin.AppConfig.String("pingan.shApiUrl"),
			frontApiUrl:      kcgin.AppConfig.String("pingan.shFrontApiUrl"),
			apiTokenUrl:      kcgin.AppConfig.String("pingan.shApiTokenUrl"),
			appId:            kcgin.AppConfig.String("pingan.shAppId"),
			mrchCode:         kcgin.AppConfig.String("pingan.shMrchCode"),
			uid:              kcgin.AppConfig.String("pingan.shUid"),
			notifyUrl:        kcgin.AppConfig.String("pingan.shNotifyUrl"),
			frontUrl:         kcgin.AppConfig.String("pingan.shFrontUrl"),
			wxMchid:          kcgin.AppConfig.String("pingan.shWXmchid"),
			wxAppid:          kcgin.AppConfig.String("pingan.shWXappid"),
			wxUrl:            kcgin.AppConfig.String("pingan.shWXurl"),
			wxNotifyUrl:      kcgin.AppConfig.String("pingan.shWXNotifyUrl"),
		}
		return nil
	case CHANNELHANGZHOU:
		PinganPay = &pinganpay{
			privateKey:       kcgin.AppConfig.String("pingan.hzPrivateKey"),
			publicKey:        kcgin.AppConfig.String("pingan.hzPublicKey"),
			privateKeySecret: kcgin.AppConfig.String("pingan.hzPrivateKeySecret"),
			traderNo:         kcgin.AppConfig.String("pingan.hzTraderNo"),
			apiUrl:           kcgin.AppConfig.String("pingan.hzApiUrl"),
			frontApiUrl:      kcgin.AppConfig.String("pingan.hzFrontApiUrl"),
			apiTokenUrl:      kcgin.AppConfig.String("pingan.hzApiTokenUrl"),
			appId:            kcgin.AppConfig.String("pingan.hzAppId"),
			mrchCode:         kcgin.AppConfig.String("pingan.hzMrchCode"),
			uid:              kcgin.AppConfig.String("pingan.hzUid"),
			notifyUrl:        kcgin.AppConfig.String("pingan.hzNotifyUrl"),
			frontUrl:         kcgin.AppConfig.String("pingan.hzFrontUrl"),
			wxMchid:          kcgin.AppConfig.String("pingan.hzWXmchid"),
			wxAppid:          kcgin.AppConfig.String("pingan.hzWXappid"),
			wxUrl:            kcgin.AppConfig.String("pingan.hzWXurl"),
			wxNotifyUrl:      kcgin.AppConfig.String("pingan.hzWXNotifyUrl"),
		}
		return nil
	default:
		return errors.New("当前城市未开通平安支付通道配置")
	}
}

/**
 * 获取请求流水号
 */
func (p *pinganpay) getTransNo() string {
	randNum := rand.Int63n(8999999999) + 1000000000
	numStr := strconv.FormatInt(randNum, 10)
	transNo := p.uid + time.Now().Format("060102") + numStr
	return transNo
}

//获取公共token
func (p *pinganpay) getApiToken() (token string, err error) {
	var priKey *rsa.PrivateKey
	var cert *x509.Certificate
	priKey, cert, err = p.getPriKeyCert()
	p.PriKey = priKey
	if err != nil {
		return
	}
	certPubKey := base64.StdEncoding.EncodeToString(cert.RawSubjectPublicKeyInfo)
	PK := replaceSpecialChar(certPubKey)
	DN := getDN(cert.Subject)
	randomNumber := fmt.Sprintf("%06v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(1000000))
	//获取签名
	var signData = map[string]interface{}{
		"ApplicationID": p.appId,
		"RandomNumber":  randomNumber,
		"SDKType":       "api",
	}
	var sign string
	sign, err = p.sign(signData, true)
	if err != nil {
		return
	}
	getTokenReq := GetTokenReq{
		ApplicationID: p.appId,
		PK:            PK,
		DN:            DN,
		RandomNumber:  randomNumber,
		RsaSign:       sign,
		SDKType:       "api",
	}
	reqByte, _ := json.Marshal(getTokenReq)
	var res string
	if res, err = p.Request(reqByte, p.apiTokenUrl); err != nil {
		logs.Info("err:", err)
		return
	}
	var replyToken = ReplyToken{}
	if err = json.Unmarshal([]byte(res), &replyToken); err != nil {
		logs.Info("err2:", err)
		return
	}
	if replyToken.ErrorCode != "OPEN-E-000000" {
		logs.Info("replyToken:", replyToken)
		return
	}
	token = replyToken.AppAccessToken
	return
}

/**
 * 获取公共参数
 */
func (p *pinganpay) getCommonData(transNo string) (maps map[string]interface{}, err error) {
	var token string
	maps = make(map[string]interface{})
	token, err = p.getApiToken()
	if err != nil {
		return
	}
	commonData := syshead{
		AppAccessToken: token,
		ApplicationID:  p.appId,
		SDKType:        "api",
		MrchCode:       p.mrchCode,
		CnsmrSeqNo:     transNo,
	}
	commDataBytes, _ := json.Marshal(commonData)
	_ = json.Unmarshal(commDataBytes, &maps)
	return
}

//合并两个map
func (p *pinganpay) arrayMergeMap(map1 map[string]interface{}, map2 map[string]interface{}) (maps map[string]interface{}) {
	maps = make(map[string]interface{})
	for k, v := range map1 {
		map2[k] = v
	}
	maps = map2
	return
}

/**
 * 强制保留两位小数
 * @return string
 */
func (p *pinganpay) changeAmount(amount string) (str string) {
	if !strings.Contains(amount, ".") {
		str = amount + ".00"
	} else {
		subAmountArr := strings.Split(amount, ".")
		subLen := len(subAmountArr[1])
		if subLen != 2 {
			if subLen < 2 {
				str = amount + strings.Repeat("0", 2-subLen)
			} else {
				str = amount[0 : (len(amount)-1)-(subLen-2)]
			}
		} else {
			str = amount
		}
	}
	return
}

//组织分账信息
func (p *pinganpay) orderRemark(orderList []pay.OrderList) (or *pay.OrderRemark) {
	if len(orderList) <= 0 {
		orderList = make([]pay.OrderList, 0)
	}
	order := make([]pay.OrderList, 0)
	for _, v := range orderList {
		v.Subamount = p.changeAmount(v.Subamount)
		v.TranFee = p.changeAmount(v.TranFee)
		order = append(order, v)
	}
	or = &pay.OrderRemark{
		Oderlist:     order,        //订单数组信息
		SFJOrdertype: "1",          //子订单模式
		Remarktype:   "SDS0100000", //备注信息
		PlantCode:    p.mrchCode,
	}
	return
}

/**
 * 前台类型交易-收银台
 */
func (p *pinganpay) PayH5(payInfo *pay.PayInfo) (string, error) {
	amount, _ := decimal.NewFromString(payInfo.RealAmount)
	title := "订单支付"
	times := time.Now().Format("20060102150405")
	data := map[string]interface{}{
		"TraderNo":          p.traderNo,
		"ClientNo":          p.uid,
		"TraderOrderNo":     payInfo.OrderSn,
		"TranAmt":           amount.Mul(decimal.NewFromInt(100)).String(),
		"OrderSendTime":     times,
		"OrderName":         title,
		"ClientType":        "h5",
		"FrontSkipUrl":      p.frontUrl,
		"CallBackNoticeUrl": p.notifyUrl,
	}
	orderRemarkBytes, _ := json.Marshal(p.orderRemark(payInfo.OrderRemark))
	data["OrderRemark"] = "[" + string(orderRemarkBytes[:]) + "]"
	sign, err := p.frontSign(data, false)
	if err != nil {
		return "", err
	}
	data["Signature"] = sign
	str := p._buildForm(data, p.frontApiUrl)
	return str, nil
}

/**
 * 微信小程序支付-平安云收款
 */
func (p *pinganpay) PayWxProgram(payInfo *pay.PayInfo) (*gjson.Result, error) {
	transNo := p.getTransNo()
	commData, err := p.getCommonData(transNo)
	logs.Info("commData", commData)
	logs.Info("err", err)
	if err != nil {
		return nil, err
	}
	amount, _ := decimal.NewFromString(payInfo.RealAmount)
	title := "订单支付"
	times := time.Now().Format("20060102150405")
	data := map[string]interface{}{
		"TraderNo":          p.traderNo,
		"TraderOrderNo":     payInfo.OrderSn,
		"OrderSendTime":     times,
		"OrderName":         title,
		"PayModeNo":         "WeixinProgram",
		"TranAmt":           amount.Mul(decimal.NewFromInt(100)).String(),
		"CallBackNoticeUrl": p.notifyUrl,
		"FrontSkipUrl":      p.frontUrl,
		"SubTraderPublicId": payInfo.AppId,
		"UserSubId":         payInfo.OpenId,
	}
	//见证宝商户信息
	orderRemarkBytes, _ := json.Marshal(p.orderRemark(payInfo.OrderRemark))
	data["OrderRemark"] = "[" + string(orderRemarkBytes[:]) + "]"
	//合并
	data = p.arrayMergeMap(commData, data)
	logs.Info("data", data)
	//执行
	result, err1 := p.exec(p.apiUrl, data)
	logs.Info("result", result.String())
	if err1 != nil {
		return nil, err1
	}
	//返回信息 按照杉德的格式返回给前端
	params := map[string]string{
		"timeStamp": result.Get("TimeStamp").String(),
		"nonceStr":  result.Get("RandomSting").String(),
		"signType":  result.Get("SignatureMode").String(),
		"paySign":   result.Get("Signature").String(),
		"package":   result.Get("ExtendString").String(),
	}
	paramsByte, _ := json.Marshal(params)
	credential := map[string]string{
		"params": string(paramsByte),
	}
	credentialByte, _ := json.Marshal(credential)
	returnData := map[string]string{
		"credential": string(credentialByte),
	}
	//returnData := map[string]string{
	//	"signatureMode":       result.Get("SignatureMode").String(),
	//	"channelOrderNo":      result.Get("ChannelOrderNo").String(),
	//	"appId":               result.Get("AppId").String(),
	//	"extendString":        result.Get("ExtendString").String(),
	//	"prepayTranSessionId": result.Get("PrepayTranSessionId").String(),
	//	"randomSting":         result.Get("RandomSting").String(),
	//}
	returnDataBytes, _ := json.Marshal(returnData)
	logs.Info("returnDataBytes: ", string(returnDataBytes))
	res := gjson.ParseBytes(returnDataBytes)
	return &res, nil
}

/**
 * 微信公众号支付-平安云收款
 */
func (p *pinganpay) PayWxOfficial(payInfo *pay.PayInfo) (*gjson.Result, error) {
	transNo := p.getTransNo()
	commData, err := p.getCommonData(transNo)
	if err != nil {
		return nil, err
	}
	amount, _ := decimal.NewFromString(payInfo.RealAmount)
	title := "订单支付"
	times := time.Now().Format("20060102150405")
	data := map[string]interface{}{
		"TraderNo":          p.traderNo,
		"TraderOrderNo":     payInfo.OrderSn,
		"OrderSendTime":     times,
		"OrderName":         title,
		"PayModeNo":         "WeixinJsapi",
		"TranAmt":           amount.Mul(decimal.NewFromInt(100)).String(),
		"CallBackNoticeUrl": p.notifyUrl,
		"FrontSkipUrl":      p.frontUrl,
		"SubTraderPublicId": payInfo.AppId,
		"UserSubId":         payInfo.OpenId,
	}
	//见证宝商户信息
	orderRemarkBytes, _ := json.Marshal(p.orderRemark(payInfo.OrderRemark))
	data["OrderRemark"] = "[" + string(orderRemarkBytes[:]) + "]"
	//合并
	data = p.arrayMergeMap(commData, data)
	//执行
	result, err1 := p.exec(p.apiUrl, data)
	if err1 != nil {
		return nil, err1
	}
	//返回信息
	returnData := map[string]string{
		"nonNativePaySkipLink": result.Get("NonNativePaySkipLink").String(),
	}
	returnDataBytes, _ := json.Marshal(returnData)
	res := gjson.ParseBytes(returnDataBytes)
	return &res, nil
}

/**
 * 微信app支付-直连
 */
func (p *pinganpay) PayWxApp(payInfo *pay.PayInfo) (*gjson.Result, error) {
	amount, _ := decimal.NewFromString(payInfo.RealAmount)
	totalAmount, _ := strconv.Atoi(amount.Mul(decimal.NewFromInt(100)).String())
	title := "订单支付"
	resData := wxPay{
		Appid:       p.wxAppid,
		Mchid:       p.wxMchid,
		Description: title,
		OutTradeNo:  payInfo.OrderSn,
		NotifyUrl:   p.wxNotifyUrl,
		Amount: wxPayAmount{
			Total:    totalAmount,
			Currency: "CNY",
		},
	}
	resByte, err := json.Marshal(resData)
	if err != nil {
		return nil, err
	}
	wxClient, err := tool.GetWXClient(payInfo.Cid)
	if err != nil {
		return nil, err
	}
	upPay, err := wxClient.Pay(context.Background(), p.wxUrl, string(resByte))
	if err != nil {
		return nil, err
	}
	upPayBytes, _ := json.Marshal(upPay)
	res := gjson.ParseBytes(upPayBytes)

	return &res, nil
}

/**
 * 支付宝app支付-直连
 */
func (p *pinganpay) PayAliApp(payInfo *pay.PayInfo) (*gjson.Result, error) {
	title := "订单支付"

	params := make(map[string]interface{})
	params["subject"] = title
	params["out_trade_no"] = payInfo.OrderSn
	params["total_amount"] = payInfo.RealAmount
	aliPayClient, err := tool.NewAliClient(payInfo.Cid)
	if err != nil {
		return nil, err
	}
	query, err := aliPayClient.GetQueryParams(params, "alipay.trade.app.pay")
	if err != nil {
		return nil, err
	}
	jsonRes := map[string]string{
		"sdk_string": string(query),
	}
	resBytes, _ := json.Marshal(jsonRes)
	res := gjson.ParseBytes(resBytes)
	return &res, nil
}

// 异步回调 InputData raw数据
func (s *pinganpay) Notify(inputData string, channelPay string) (*gjson.Result, error) {
	dataJson := gjson.Parse(inputData)
	if dataJson.Exists() {
		maps := make(map[string]interface{})
		dataJson.ForEach(func(key, value gjson.Result) bool {
			//channelArea 和 channelPay 字段为每个异步通知结果中新增的字段
			if key.String() != "channelArea" && key.String() != "channelPay" {
				maps[key.String()] = value.String()
			}
			return true
		})
		if channelPay == CHANNELPAY_pingan {
			//平安云收款
			if err := s.notifyVerify(maps); err != nil {
				return nil, err
			}
		} else if channelPay == CHANNELPAY_ali {
			//支付宝直连
			channelArea := int(dataJson.Get("channelArea").Int())
			aliClient, err := tool.NewAliClient(channelArea)
			if err != nil {
				return nil, err
			}
			if err := aliClient.Notify(maps); err != nil {
				return nil, err
			}
		} else if channelPay == CHANNELPAY_wx {
			//微信直连
			channelArea := int(dataJson.Get("channelArea").Int())
			wxClient, err := tool.GetWXClient(channelArea)
			if err != nil {
				return nil, err
			}
			data, err := wxClient.Notify([]byte(maps["body"].(string)), []byte(maps["header"].(string)))
			if err != nil {
				return nil, err
			}
			dataJson = gjson.Parse(data)
		} else {
			return nil, errors.New("unkown notify channel pay")
		}
	} else {
		return nil, errors.New("verify data format err")
	}
	return &dataJson, nil
}

/**
 * 创建post表单
 */
func (p *pinganpay) _buildForm(data map[string]interface{}, url string) (sHtml string) {
	sHtml = ""
	sHtml = sHtml + fmt.Sprintf("<form id='paysubmit' name='paysubmit' action='%s' method='POST' >\n", url)
	for k, v := range data {
		sHtml += fmt.Sprintf("<input type='hidden' name='%s' value='%s' />%s", k, v, "\n")
	}
	sHtml += "</form>"
	sHtml += "<script>document.forms['paysubmit'].submit();</script>"
	logs.Info("平安支付begin")
	logs.Info(sHtml)
	logs.Info("平安支付end")
	return
}

// 执行
func (p *pinganpay) exec(url string, data map[string]interface{}) (*gjson.Result, error) {
	logs.Info("url", url)
	sign, err := p.sign(data, false)
	logs.Info("sign:", sign)
	logs.Info("err:", err)
	if err != nil {
		return nil, err
	}
	data["RsaSign"] = sign
	reqBytes, _ := json.Marshal(data)
	result, err1 := p.Request(reqBytes, url)
	logs.Info("result", result)
	if err1 != nil {
		logs.Info("err", err1)
		return nil, err1
	}
	rjson := gjson.Parse(result)
	if rjson.Get("TxnReturnCode").String() != "T0000" {
		return nil, errors.New(rjson.Get("TxnReturnMsg").String())
	}
	return &rjson, nil
}

//过滤特殊字符
func replaceSpecialChar(str string) string {
	str = strings.Replace(str, " ", "", -1)
	str = strings.Replace(str, "　", "", -1)
	str = strings.Replace(str, "\n", "", -1)
	str = strings.Replace(str, "\r", "", -1)
	str = strings.Replace(str, "\t", "", -1)
	str = strings.Replace(str, "+", "%2B", -1)
	str = strings.Replace(str, "=", "%3D", -1)
	return str
}

//获取DN
func getDN(cert pkix.Name) string {
	dn := "CN=" + cert.CommonName + ",OU=" + cert.OrganizationalUnit[1] + ",OU=" + cert.OrganizationalUnit[0] + ",O=" + cert.Organization[0] + ",C=" + cert.Country[0]
	//dn := "CN=,OU=,OU=,O=DefaultCompanyLtd,C=XX"
	dn = replaceSpecialChar(dn)
	return dn
}

//获取私钥和证书
func (p *pinganpay) getPriKeyCert() (*rsa.PrivateKey, *x509.Certificate, error) {
	f, err := os.Open(p.privateKey)
	if err != nil {
		return nil, nil, err
	}
	pbytes, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, nil, err
	}
	priKey, cert, err := pkcs12.Decode(pbytes, p.privateKeySecret)
	if err != nil {
		return nil, nil, errors.New("解密失败")
	}
	private := priKey.(*rsa.PrivateKey)
	return private, cert, nil
}

//获取公钥证书
func (p *pinganpay) getPubKeyCert() (*rsa.PublicKey, error) {
	certPEMBlock, err := ioutil.ReadFile(p.publicKey)
	if err != nil {
		return nil, err
	}
	certDERBlock, _ := pem.Decode(certPEMBlock)
	if certDERBlock == nil {
		return nil, err
	}
	x509Cert, err := x509.ParseCertificate(certDERBlock.Bytes)
	if err != nil {
		return nil, err
	}
	pub := x509Cert.PublicKey.(*rsa.PublicKey)
	return pub, nil
}

//异步通知验签名
func (p *pinganpay) notifyVerify(verifyMap map[string]interface{}) error {
	vsign := ""
	if _, ok := verifyMap["Signature"]; ok {
		vsign = verifyMap["Signature"].(string)
		delete(verifyMap, "Signature")
	}
	pub, err := p.getPubKeyCert()
	if err != nil {
		return err
	}
	vsignBytes, _ := base64.StdEncoding.DecodeString(vsign)
	keys := []string{}
	for k, _ := range verifyMap {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	strs := ""
	for _, v := range keys {
		if verifyMap[v] == "" {
			continue
		}
		strs += v + "=" + verifyMap[v].(string) + "&"
	}
	h := sha256.New()
	h.Write([]byte(strs))
	d := h.Sum(nil)
	if err := rsa.VerifyPKCS1v15(pub, crypto.SHA256, d, vsignBytes); err != nil {
		return err
	}
	return nil
}

//前台类型签名
func (p *pinganpay) frontSign(signMap map[string]interface{}, repSpecChar bool) (sign string, err error) {
	if p.PriKey == nil {
		p.PriKey, _, _ = p.getPriKeyCert()
	}
	keys := []string{}
	for k, _ := range signMap {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	strs := ""
	for _, v := range keys {
		if signMap[v] == "" {
			continue
		}
		strs += v + "=" + signMap[v].(string) + "&"
	}
	h := sha256.New()
	h.Write([]byte(strs))
	d := h.Sum(nil)
	signByte, err := rsa.SignPKCS1v15(crand.Reader, p.PriKey, crypto.SHA256, d)
	if err != nil {
		return "", err
	}
	sign = base64.StdEncoding.EncodeToString(signByte)
	if repSpecChar {
		sign = replaceSpecialChar(sign)
	}
	return
}

//后台类签名
func (p *pinganpay) sign(signMap map[string]interface{}, repSpecChar bool) (sign string, err error) {
	if p.PriKey == nil {
		p.PriKey, _, _ = p.getPriKeyCert()
	}
	keys := []string{}
	for k, _ := range signMap {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	strs := ""
	for _, v := range keys {
		if signMap[v] == "" {
			continue
		}
		strs += v + "=" + signMap[v].(string) + "&"
	}
	h := md5.New()
	h.Write([]byte(strs))
	d := h.Sum(nil)
	signByte, err := rsa.SignPKCS1v15(crand.Reader, p.PriKey, crypto.MD5, d)
	if err != nil {
		return "", err
	}
	sign = base64.StdEncoding.EncodeToString(signByte)
	if repSpecChar {
		sign = replaceSpecialChar(sign)
	}
	return
}

//发送请求
func (p *pinganpay) Request(req []byte, url string) (res string, err error) {
	var request *http.Request
	logs.Info("平安云收款-请求报文：", string(req))
	request, err = http.NewRequest("POST", url, bytes.NewBuffer(req))
	if err != nil {
		return
	}
	request.Header.Set("Content-Type", "application/json;charset=utf-8")
	request.Header.Set("Content-Length", strconv.Itoa(len(req)))
	request.Header.Set("Accept-Encoding", "*/*")
	client := &http.Client{}
	var response *http.Response
	response, err = client.Do(request)
	if err != nil {
		return
	}
	defer response.Body.Close()
	if response.StatusCode == http.StatusOK {
		body, _ := ioutil.ReadAll(response.Body)
		res = string(body)
		return
	}
	err = errors.New("request status:" + response.Status + ",url :" + url)
	return
}
